{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "bd66abf9",
   "metadata": {},
   "source": [
    "## 导库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "29c474d6",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import os\n",
    "import sys\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "\n",
    "plt.rcParams[\"font.sans-serif\"] = [\"SimHei\"]\n",
    "plt.rcParams[\"axes.unicode_minus\"] = False\n",
    "\n",
    "# 导入评估函数和配置\n",
    "from config import *"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "263bd266",
   "metadata": {},
   "source": [
    "## 创建模拟训练数据"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63689fa6",
   "metadata": {},
   "source": [
    "将训练数据改为"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "fb2953ad",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "训练数据形状: (635729, 12)\n"
     ]
    }
   ],
   "source": [
    "# 加载训练数据\n",
    "def load_train_data():\n",
    "    \"\"\"\n",
    "    加载训练数据并返回DataFrame\n",
    "    \"\"\"\n",
    "    train_data = pd.read_csv(f\"{DATA_DIR}/train.csv\")\n",
    "    print(f\"训练数据形状: {train_data.shape}\")\n",
    "    return train_data\n",
    "\n",
    "\n",
    "train_data = load_train_data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "b2814381",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.microsoft.datawrangler.viewer.v0+json": {
       "columns": [
        {
         "name": "index",
         "rawType": "int64",
         "type": "integer"
        },
        {
         "name": "股票代码",
         "rawType": "int64",
         "type": "integer"
        },
        {
         "name": "日期",
         "rawType": "datetime64[ns]",
         "type": "datetime"
        },
        {
         "name": "开盘",
         "rawType": "float64",
         "type": "float"
        },
        {
         "name": "收盘",
         "rawType": "float64",
         "type": "float"
        },
        {
         "name": "最高",
         "rawType": "float64",
         "type": "float"
        },
        {
         "name": "最低",
         "rawType": "float64",
         "type": "float"
        },
        {
         "name": "成交量",
         "rawType": "int64",
         "type": "integer"
        },
        {
         "name": "成交额",
         "rawType": "float64",
         "type": "float"
        },
        {
         "name": "振幅",
         "rawType": "float64",
         "type": "float"
        },
        {
         "name": "涨跌额",
         "rawType": "float64",
         "type": "float"
        },
        {
         "name": "换手率",
         "rawType": "float64",
         "type": "float"
        },
        {
         "name": "涨跌幅",
         "rawType": "float64",
         "type": "float"
        }
       ],
       "ref": "25c0a403-4312-4927-a8c9-0cb7c3f85561",
       "rows": [
        [
         "394187",
         "1",
         "2015-04-20 00:00:00",
         "11.81",
         "11.14",
         "11.89",
         "11.02",
         "3447257",
         "5776438016.0",
         "7.46",
         "-0.53",
         "2.92",
         "-4.54"
        ],
        [
         "396619",
         "2",
         "2015-04-20 00:00:00",
         "6.9",
         "6.33",
         "7.22",
         "6.31",
         "5933165",
         "8718400512.0",
         "13.4",
         "-0.46",
         "6.11",
         "-6.77"
        ],
        [
         "398916",
         "63",
         "2015-04-20 00:00:00",
         "19.02",
         "19.87",
         "21.11",
         "18.43",
         "2199754",
         "5979197952.0",
         "14.14",
         "0.91",
         "7.85",
         "4.8"
        ],
        [
         "401274",
         "100",
         "2015-04-20 00:00:00",
         "4.82",
         "4.87",
         "5.03",
         "4.68",
         "7135405",
         "4378264320.0",
         "7.22",
         "0.02",
         "8.73",
         "0.41"
        ],
        [
         "403540",
         "157",
         "2015-04-20 00:00:00",
         "5.53",
         "5.82",
         "6.31",
         "5.42",
         "6498947",
         "5303233280.0",
         "15.61",
         "0.12",
         "10.38",
         "2.11"
        ]
       ],
       "shape": {
        "columns": 12,
        "rows": 5
       }
      },
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>股票代码</th>\n",
       "      <th>日期</th>\n",
       "      <th>开盘</th>\n",
       "      <th>收盘</th>\n",
       "      <th>最高</th>\n",
       "      <th>最低</th>\n",
       "      <th>成交量</th>\n",
       "      <th>成交额</th>\n",
       "      <th>振幅</th>\n",
       "      <th>涨跌额</th>\n",
       "      <th>换手率</th>\n",
       "      <th>涨跌幅</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>394187</th>\n",
       "      <td>1</td>\n",
       "      <td>2015-04-20</td>\n",
       "      <td>11.81</td>\n",
       "      <td>11.14</td>\n",
       "      <td>11.89</td>\n",
       "      <td>11.02</td>\n",
       "      <td>3447257</td>\n",
       "      <td>5.776438e+09</td>\n",
       "      <td>7.46</td>\n",
       "      <td>-0.53</td>\n",
       "      <td>2.92</td>\n",
       "      <td>-4.54</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>396619</th>\n",
       "      <td>2</td>\n",
       "      <td>2015-04-20</td>\n",
       "      <td>6.90</td>\n",
       "      <td>6.33</td>\n",
       "      <td>7.22</td>\n",
       "      <td>6.31</td>\n",
       "      <td>5933165</td>\n",
       "      <td>8.718401e+09</td>\n",
       "      <td>13.40</td>\n",
       "      <td>-0.46</td>\n",
       "      <td>6.11</td>\n",
       "      <td>-6.77</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>398916</th>\n",
       "      <td>63</td>\n",
       "      <td>2015-04-20</td>\n",
       "      <td>19.02</td>\n",
       "      <td>19.87</td>\n",
       "      <td>21.11</td>\n",
       "      <td>18.43</td>\n",
       "      <td>2199754</td>\n",
       "      <td>5.979198e+09</td>\n",
       "      <td>14.14</td>\n",
       "      <td>0.91</td>\n",
       "      <td>7.85</td>\n",
       "      <td>4.80</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>401274</th>\n",
       "      <td>100</td>\n",
       "      <td>2015-04-20</td>\n",
       "      <td>4.82</td>\n",
       "      <td>4.87</td>\n",
       "      <td>5.03</td>\n",
       "      <td>4.68</td>\n",
       "      <td>7135405</td>\n",
       "      <td>4.378264e+09</td>\n",
       "      <td>7.22</td>\n",
       "      <td>0.02</td>\n",
       "      <td>8.73</td>\n",
       "      <td>0.41</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>403540</th>\n",
       "      <td>157</td>\n",
       "      <td>2015-04-20</td>\n",
       "      <td>5.53</td>\n",
       "      <td>5.82</td>\n",
       "      <td>6.31</td>\n",
       "      <td>5.42</td>\n",
       "      <td>6498947</td>\n",
       "      <td>5.303233e+09</td>\n",
       "      <td>15.61</td>\n",
       "      <td>0.12</td>\n",
       "      <td>10.38</td>\n",
       "      <td>2.11</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "        股票代码         日期     开盘     收盘     最高     最低      成交量           成交额  \\\n",
       "394187     1 2015-04-20  11.81  11.14  11.89  11.02  3447257  5.776438e+09   \n",
       "396619     2 2015-04-20   6.90   6.33   7.22   6.31  5933165  8.718401e+09   \n",
       "398916    63 2015-04-20  19.02  19.87  21.11  18.43  2199754  5.979198e+09   \n",
       "401274   100 2015-04-20   4.82   4.87   5.03   4.68  7135405  4.378264e+09   \n",
       "403540   157 2015-04-20   5.53   5.82   6.31   5.42  6498947  5.303233e+09   \n",
       "\n",
       "           振幅   涨跌额    换手率   涨跌幅  \n",
       "394187   7.46 -0.53   2.92 -4.54  \n",
       "396619  13.40 -0.46   6.11 -6.77  \n",
       "398916  14.14  0.91   7.85  4.80  \n",
       "401274   7.22  0.02   8.73  0.41  \n",
       "403540  15.61  0.12  10.38  2.11  "
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_data[\"日期\"] = pd.to_datetime(train_data[\"日期\"], format=\"%Y-%m-%d\")\n",
    "train_data = train_data.sort_values(by=[\"日期\", \"股票代码\"])\n",
    "train_data.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fffdd9ac",
   "metadata": {},
   "source": [
    "截取2015年4月20日至2025年4月15日的数据,保存为simulated-train.csv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "4dcfb008",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Data from 2015-04-20 to 2025-04-15 saved to ../../data\\simulated-train.csv\n",
      "Shape of filtered data: (634829, 12)\n"
     ]
    }
   ],
   "source": [
    "start_date = \"2015-04-20\"\n",
    "end_date = \"2025-04-15\"\n",
    "filtered_data = train_data[\n",
    "    (train_data[\"日期\"] >= start_date) & (train_data[\"日期\"] <= end_date)\n",
    "]\n",
    "\n",
    "output_path = os.path.join(DATA_DIR, \"simulated-train.csv\")\n",
    "\n",
    "filtered_data = filtered_data.sort_values(by=[\"股票代码\", \"日期\"])\n",
    "filtered_data.to_csv(output_path, index=False)\n",
    "\n",
    "print(f\"Data from {start_date} to {end_date} saved to {output_path}\")\n",
    "print(f\"Shape of filtered data: {filtered_data.shape}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb853b0c",
   "metadata": {},
   "source": [
    "保存原数据为simulated-test.csv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "11317e85",
   "metadata": {},
   "outputs": [],
   "source": [
    "output_path = os.path.join(DATA_DIR, \"simulated-test.csv\")\n",
    "train_data = train_data.sort_values(by=[\"股票代码\", \"日期\"])\n",
    "train_data.to_csv(output_path, index=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "137f1cb8",
   "metadata": {},
   "source": [
    "## 计算simulated-test.csv的结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "7a5ed544",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "训练数据形状: (635729, 12)\n",
      "训练数据预览:\n",
      "     股票代码          日期    开盘    收盘    最高    最低      成交量           成交额    振幅  \\\n",
      "0  600000  2015-04-20  9.47  8.89  9.47  8.68  5724358  1.044673e+10  8.42   \n",
      "1  600000  2015-04-21  8.79  9.07  9.10  8.79  3681947  6.615541e+09  3.49   \n",
      "2  600000  2015-04-22  9.17  9.31  9.35  9.02  4207667  7.712131e+09  3.64   \n",
      "3  600000  2015-04-23  9.31  9.12  9.41  9.04  3635936  6.675542e+09  3.97   \n",
      "4  600000  2015-04-24  8.82  8.74  8.98  8.59  4229271  7.509013e+09  4.28   \n",
      "\n",
      "    涨跌额   换手率   涨跌幅  \n",
      "0 -0.49  3.84 -5.22  \n",
      "1  0.18  2.47  2.02  \n",
      "2  0.24  2.82  2.65  \n",
      "3 -0.19  2.44 -2.04  \n",
      "4 -0.38  2.83 -4.17  \n",
      "\n",
      "涨跌幅统计信息:\n",
      "count    300.000000\n",
      "mean       0.000400\n",
      "std        1.234945\n",
      "min       -4.250000\n",
      "25%       -0.772500\n",
      "50%        0.000000\n",
      "75%        0.610000\n",
      "max        4.960000\n",
      "Name: 涨跌幅, dtype: float64\n",
      "\n",
      "涨幅最大的10支股票:\n",
      "[2463, 963, 300433, 63, 2555, 300502, 603799, 807, 425, 2241]\n",
      "\n",
      "涨幅最小的10支股票:\n",
      "[1289, 600588, 300896, 688506, 688041, 603288, 603392, 300661, 975, 605499]\n",
      "\n",
      "真实涨跌幅排名已保存到: ../../data/simulated-ranks.csv\n"
     ]
    }
   ],
   "source": [
    "# 获取涨幅最大和最小的股票\n",
    "def get_top_bottom_stocks(data, n=10):\n",
    "    \"\"\"\n",
    "    获取涨幅最大和最小的n支股票\n",
    "\n",
    "    Args:\n",
    "        data: 包含股票数据的DataFrame\n",
    "        n: 要获取的股票数量\n",
    "\n",
    "    Returns:\n",
    "        tuple: (涨幅最大的n支股票, 涨幅最小的n支股票)\n",
    "    \"\"\"\n",
    "    # 获取最后一个日期的数据\n",
    "    last_date = data[\"日期\"].max()\n",
    "    last_data = data[data[\"日期\"] == last_date]\n",
    "\n",
    "    # 按涨跌幅排序\n",
    "    sorted_data = last_data.sort_values(by=\"涨跌幅\", ascending=False)\n",
    "\n",
    "    # 获取涨幅最大和最小的n支股票\n",
    "    top_n_stocks = sorted_data.head(n)[\"股票代码\"].tolist()\n",
    "    bottom_n_stocks = sorted_data.tail(n)[\"股票代码\"].tolist()\n",
    "\n",
    "    return top_n_stocks, bottom_n_stocks\n",
    "\n",
    "\n",
    "# 分析训练数据的涨跌幅\n",
    "def analyze_price_changes(data):\n",
    "    \"\"\"\n",
    "    分析训练数据中的涨跌幅\n",
    "\n",
    "    Args:\n",
    "        data: 包含股票数据的DataFrame\n",
    "    \"\"\"\n",
    "    # 获取最后一个日期的数据\n",
    "    last_date = data[\"日期\"].max()\n",
    "    last_data = data[data[\"日期\"] == last_date]\n",
    "\n",
    "    # 显示涨跌幅的统计信息\n",
    "    print(\"\\n涨跌幅统计信息:\")\n",
    "    print(last_data[\"涨跌幅\"].describe())\n",
    "\n",
    "    # 获取涨幅最大和最小的10支股票\n",
    "    top_10_stocks, bottom_10_stocks = get_top_bottom_stocks(data)\n",
    "\n",
    "    print(\"\\n涨幅最大的10支股票:\")\n",
    "    print(top_10_stocks)\n",
    "\n",
    "    print(\"\\n涨幅最小的10支股票:\")\n",
    "    print(bottom_10_stocks)\n",
    "\n",
    "    # 创建结果DataFrame（用于评估或比较）\n",
    "    result_df = pd.DataFrame(\n",
    "        {\"涨幅最大股票代码\": top_10_stocks, \"涨幅最小股票代码\": bottom_10_stocks}\n",
    "    )\n",
    "\n",
    "    # 保存结果\n",
    "    temp_result_path = f\"{DATA_DIR}/simulated-ranks.csv\"\n",
    "    result_df.to_csv(temp_result_path, index=False)\n",
    "    print(f\"\\n真实涨跌幅排名已保存到: {temp_result_path}\")\n",
    "\n",
    "    return top_10_stocks, bottom_10_stocks, temp_result_path\n",
    "\n",
    "\n",
    "# 主执行代码\n",
    "train_data = load_train_data()\n",
    "\n",
    "# 显示数据的前几行\n",
    "print(\"训练数据预览:\")\n",
    "print(train_data.head())\n",
    "\n",
    "# 分析涨跌幅\n",
    "top_stocks, bottom_stocks, true_ranks_path = analyze_price_changes(train_data)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "383d712a",
   "metadata": {},
   "source": [
    "## 模拟得分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "615a11c4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最终得分: nan\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\xiaof\\AppData\\Local\\Temp\\ipykernel_17748\\182350232.py:70: ConstantInputWarning: An input array is constant; the correlation coefficient is not defined.\n",
      "  rank_corr_up, _ = spearmanr(true_top_ranks, pred_top_ranks)\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from scipy.stats import spearmanr\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "from scipy.stats import spearmanr\n",
    "\n",
    "\n",
    "def calculate_final_score_from_files(pred_file_path, true_file_path):\n",
    "    \"\"\"\n",
    "    Calculate the final score based on predicted and true stock rankings from CSV files.\n",
    "\n",
    "    Parameters:\n",
    "    - pred_file_path (str): Path to the CSV file with predicted stock codes\n",
    "    - true_file_path (str): Path to the CSV file with true stock codes\n",
    "\n",
    "    Returns:\n",
    "    - float: Final score\n",
    "    \"\"\"\n",
    "    # Read the CSV files\n",
    "    pred_data = pd.read_csv(pred_file_path)\n",
    "    true_data = pd.read_csv(true_file_path)\n",
    "\n",
    "    # Extract top 10 and bottom 10 stock codes\n",
    "    pred_top_10 = pred_data[\"涨幅最大股票代码\"].tolist()\n",
    "    pred_bottom_10 = pred_data[\"涨幅最小股票代码\"].tolist()\n",
    "    true_top_10 = true_data[\"涨幅最大股票代码\"].tolist()\n",
    "    true_bottom_10 = true_data[\"涨幅最小股票代码\"].tolist()\n",
    "\n",
    "    # Calculate F1 scores for top 10\n",
    "    true_pos_top = len(set(true_top_10) & set(pred_top_10))\n",
    "    precision_up = true_pos_top / 10\n",
    "    recall_up = true_pos_top / 10\n",
    "    f1_up = (\n",
    "        (2 * precision_up * recall_up) / (precision_up + recall_up)\n",
    "        if (precision_up + recall_up) > 0\n",
    "        else 0\n",
    "    )\n",
    "\n",
    "    # Calculate F1 scores for bottom 10\n",
    "    true_pos_bottom = len(set(true_bottom_10) & set(pred_bottom_10))\n",
    "    precision_down = true_pos_bottom / 10\n",
    "    recall_down = true_pos_bottom / 10\n",
    "    f1_down = (\n",
    "        (2 * precision_down * recall_down) / (precision_down + recall_down)\n",
    "        if (precision_down + recall_down) > 0\n",
    "        else 0\n",
    "    )\n",
    "\n",
    "    # Compute predicted ranks based on order in predicted lists\n",
    "    true_top_ranks = np.arange(10)  # 0 to 9 for true top 10\n",
    "    pred_top_ranks = np.array(\n",
    "        [\n",
    "            pred_top_10.index(stock) if stock in pred_top_10 else 10\n",
    "            for stock in true_top_10\n",
    "        ]\n",
    "    )\n",
    "    true_bottom_ranks = np.arange(10)  # 0 to 9 for true bottom 10\n",
    "    pred_bottom_ranks = np.array(\n",
    "        [\n",
    "            pred_bottom_10.index(stock) if stock in pred_bottom_10 else 10\n",
    "            for stock in true_bottom_10\n",
    "        ]\n",
    "    )\n",
    "\n",
    "    pred_top_ranks = np.where(pred_top_ranks == 10, 11, pred_top_ranks)\n",
    "    pred_bottom_ranks = np.where(pred_bottom_ranks == 10, 11, pred_bottom_ranks)\n",
    "\n",
    "    try:\n",
    "        rank_corr_up, _ = spearmanr(true_top_ranks, pred_top_ranks)\n",
    "    except Exception:\n",
    "        rank_corr_up = 0.0  # Fallback to 0 if correlation is undefined\n",
    "\n",
    "    try:\n",
    "        rank_corr_down, _ = spearmanr(true_bottom_ranks, pred_bottom_ranks)\n",
    "    except Exception:\n",
    "        rank_corr_down = 0.0  # Fallback to 0 if correlation is undefined\n",
    "\n",
    "    final_score = (\n",
    "        0.2 * f1_up + 0.2 * f1_down + 0.3 * rank_corr_up + 0.3 * rank_corr_down\n",
    "    )\n",
    "\n",
    "    return final_score\n",
    "\n",
    "\n",
    "# temp_result_path = f\"{DATA_DIR}/simulated-result.csv\"\n",
    "temp_result_path = f\"{OUTPUT_DIR}/simulated-result.csv\"\n",
    "true_ranks_path = f\"{DATA_DIR}/simulated-ranks.csv\"\n",
    "\n",
    "# 计算最终得分\n",
    "final_score = calculate_final_score_from_files(temp_result_path, true_ranks_path)\n",
    "print(f\"最终得分: {final_score:.4f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7194c9a1",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
